#pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include "Com.hpp"
#include <memory>
#include <iostream>
#include "Log.hpp"
using namespace LogMoudle;
namespace SocketMoule {

class Nocopyable {
public:
    Nocopyable() = default;
    Nocopyable(const Nocopyable&)            = delete;
    Nocopyable& operator=(const Nocopyable&) = delete;
};

class Socket : public Nocopyable {
public:
    virtual ~Socket() = default;
    virtual void CreateSocket() = 0;
    virtual void Bind()         = 0;
    virtual void Listen()       = 0;
    virtual int  Accept()       = 0;
};

class Tcpserver : public Socket {
private:
    int sockfd_ = -1;
    int port_;
    Netaddr addr_;
public:
    explicit Tcpserver(int port) : port_(port), addr_(port) {
        CreateSocket();
        Bind();
        Listen();
    }
    ~Tcpserver() override { if (sockfd_ >= 0) ::close(sockfd_); }

    void CreateSocket() override {
        sockfd_ = ::socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd_ < 0) { exit(error); }
        
    }

    void Bind() override {
        if (::bind(sockfd_, addr_.getAddr(), addr_.getLen()) < 0) {
            LOG(LogLevel::ERROR)<<"bind failed"; exit(error);
        }
        LOG(LogLevel::INFO)<<"bind success";
    }

    void Listen() override {
        if (::listen(sockfd_, 128) < 0) { exit(error); }
        LOG(LogLevel::INFO)<<"listen success";
    }

    int Accept() override {
        struct sockaddr_in cli;
        socklen_t len = sizeof(cli);
        int conn = ::accept(sockfd_, (struct sockaddr*)&cli, &len);
        if (conn < 0) { exit(error); }
        return conn;
    }

    int getfd() const { return sockfd_; }
};

} 